Skip to content

Dragging on frame body now always moves the frame#10

Merged
kaznaan merged 5 commits intoluma/v4.4.xfrom
gray/frame-body-drag-moves
Mar 2, 2026
Merged

Dragging on frame body now always moves the frame#10
kaznaan merged 5 commits intoluma/v4.4.xfrom
gray/frame-body-drag-moves

Conversation

@graycrawford
Copy link
Copy Markdown
Collaborator

Dragging on a frame body now always moves the frame instead of starting a rect selection.

@graycrawford graycrawford requested a review from kaznaan March 2, 2026 17:32
@cursor
Copy link
Copy Markdown

cursor Bot commented Mar 2, 2026

PR Summary

Medium Risk
Medium risk because it changes core selection/dragging behavior in SelectTool, which may affect wrap/brush selection semantics and how frames or other shapes are picked during drag gestures.

Overview
Dragging on a frame body is now biased toward moving the frame rather than falling into rectangle selection.

Brush-selection logic now always excludes frames from edge/intersection hit-testing, meaning frames are only selected by brushing when the brush fully contains them.

Removes the special-case drag behavior for grid shapes (and its label hit-testing) that previously cleared selection and transitioned into brushing when dragging on the grid body.

Written by Cursor Bugbot for commit 411e4c6. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Dead code: didHitGridLabel is now unused
    • Removed the unused didHitGridLabel property declaration, the grid label detection logic in onEnter, and the Group2d import that was only used by that dead code.

Create PR

Or push these changes by commenting:

@cursor push 5fa99b9458
Preview (5fa99b9458)
diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts
--- a/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts
+++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts
@@ -1,4 +1,4 @@
-import { Group2d, StateNode, TLPointerEventInfo, TLShape } from '@tldraw/editor'
+import { StateNode, TLPointerEventInfo, TLShape } from '@tldraw/editor'
 import { isOverArrowLabel } from '../../../shapes/arrow/arrowLabel'
 import { getTextLabels } from '../../../utils/shapes/shapes'
 
@@ -11,7 +11,6 @@
 
 	didCtrlOnEnter = false
 	didSelectOnEnter = false
-	didHitGridLabel = false
 
 	override onEnter(info: TLPointerEventInfo & { target: 'shape' }) {
 		const selectedShapeIds = this.editor.getSelectedShapeIds()
@@ -23,19 +22,6 @@
 		this.hitShape = info.shape
 		this.isDoubleClick = false
 		this.didCtrlOnEnter = accelKey
-		this.didHitGridLabel = false
-		if ((info.shape as any).type === 'grid') {
-			const geometry = this.editor.getShapeGeometry(info.shape)
-			if (geometry instanceof Group2d) {
-				const pointInShapeSpace = this.editor.getPointInShapeSpace(info.shape, currentPagePoint)
-				for (const child of geometry.children) {
-					if (child.isLabel && child.isPointInBounds(pointInShapeSpace)) {
-						this.didHitGridLabel = true
-						break
-					}
-				}
-			}
-		}
 		const outermostSelectingShape = this.editor.getOutermostSelectableShape(info.shape)
 		const selectedAncestor = this.editor.findShapeAncestor(outermostSelectingShape, (parent) =>
 			selectedShapeIds.includes(parent.id)

Removes the isWrapping check so Cmd/Ctrl+drag selects assets by
intersection instead of requiring full enclosure. Only frames
still require full enclosure regardless of modifier keys.

Made-with: Cursor
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Wrap mode selection broken by removed isWrapping check
    • Restored the isWrapping condition in the guard at line 197, which was accidentally removed, making wrap mode functional again.
  • ✅ Fixed: Frame-like shapes lose hit-test blocking behavior
    • Changed isShapeOfType(shape, 'frame') to isShapeFrame(shape) to maintain consistent behavior for custom frame-like shapes.

Create PR

Or push these changes by commenting:

@cursor push 38be269d62
Preview (38be269d62)
diff --git a/packages/editor/src/lib/editor/Editor.ts b/packages/editor/src/lib/editor/Editor.ts
--- a/packages/editor/src/lib/editor/Editor.ts
+++ b/packages/editor/src/lib/editor/Editor.ts
@@ -5330,7 +5330,7 @@
 				}
 			}
 
-			if (this.isShapeOfType(shape, 'frame')) {
+			if (this.isShapeFrame(shape)) {
 				// On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
 				// this prevents clicks from passing through the body of a frame to shapes behind it.
 

diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts
--- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts
+++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts
@@ -194,7 +194,7 @@
 
 			// If we're in wrap mode and the brush did not fully encloses the shape, it's a miss
 			// We also skip frames unless we've completely selected the frame.
-			if (editor.isShapeFrame(shape)) {
+			if (isWrapping || editor.isShapeFrame(shape)) {
 				continue testAllShapes
 			}

Comment thread packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts
Comment thread packages/editor/src/lib/editor/Editor.ts
@kaznaan kaznaan merged commit 31fff3d into luma/v4.4.x Mar 2, 2026
11 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants